home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume89 / unix / find12.1 < prev    next >
Text File  |  1989-03-15  |  23KB  |  1,025 lines

  1. Path: xanth!ukma!mailrus!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v89i046:  find - file system searcher v1.2
  5. Message-ID: <12219@swan.ulowell.edu>
  6. Date: 15 Mar 89 15:22:56 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 1014
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: munnari!bhpese.oz.au!rodney@uunet.UU.NET  (Rodney Lewis)
  12. Posting-number: Volume 89, Issue 46
  13. Archive-name: unix/find12.1
  14.  
  15. #    This is a shell archive.
  16. #    Remove everything above and including the cut line.
  17. #    Then run the rest of the file through sh.
  18. #----cut here-----cut here-----cut here-----cut here----#
  19. #!/bin/sh
  20. # shar:    Shell Archiver
  21. #    Run the following text with /bin/sh to create:
  22. #    find.c
  23. #    makefile
  24. # This archive created: Wed Mar 15 10:21:11 1989
  25. cat << \SHAR_EOF > find.c
  26. /**********************************************************************/
  27. /*                                                                    */
  28. /* find - Amiga Version 1.2                                           */
  29. /*                                                                    */
  30. /* Copyright (c) 1988,89 - Rodney Lewis                               */
  31. /*                                                                    */
  32. /* This program is freely copyable and distributable. All copyrights  */
  33. /* are reserved by the author. You may give copies of this program to */
  34. /* anyone you wish but you may not sell it.                           */
  35. /*                                                                    */
  36. /* Pattern matching routine taken from Matt Dillon's csh program;     */
  37. /* reproduced by permission.                                          */
  38. /*                                                                    */
  39. /* Changes from Version 1.0:                                          */
  40. /*                                                                    */
  41. /*   - dynamic allocation of file name space when recursing down      */
  42. /*     the directory tree and when executing commands.                */
  43. /*                                                                    */
  44. /*   - changed comparison to assignment on line 652 of find.c.        */
  45. /*     Though this makes no difference to the program, (i.e the       */
  46. /*     line doesn't really need to be there in the first place),      */
  47. /*     it was incorrect code. Thanks to Hume Smith, Acadia U.         */
  48. /*                                                                    */
  49. /*   - added support for the 1.3 hidden, script, pure and archive     */
  50. /*     bits in "-perm" primary.                                       */
  51. /*                                                                    */
  52. /*   - added extra primary "-prot" to test for indiviual protection   */
  53. /*     bits. "-perm" tests only for an exact permissions match. This  */
  54. /*     allows the you (for example) to search for all files that have */
  55. /*     not been archived using "! -prot a".                           */
  56. /*                                                                    */
  57. /*   - changed find so the path name used for each file is relative   */
  58. /*     to the current directory; which is as it should be. In V1.0,   */
  59. /*     the full path name of each file from the root of the device    */
  60. /*     was always used.                                               */
  61. /*                                                                    */
  62. /**********************************************************************/
  63.  
  64. /**********************************************************************/
  65. /*                                                                    */
  66. /* find    - searches the directory hierachy looking for files that   */
  67. /*           match a given boolean expression. Based  on  the  U**X   */
  68. /*           find command.                                            */
  69. /*                                                                    */
  70. /**********************************************************************/
  71.  
  72. #include <exec/types.h>
  73. #include <exec/memory.h>
  74. #include <libraries/dosextens.h>
  75. #include <stdio.h>
  76. #include <functions.h>
  77.  
  78. /* define new 1.3 protection bits */
  79.  
  80. #ifndef FIBB_HIDDEN
  81. #define FIBB_HIDDEN    7L
  82. #define FIBB_SCRIPT    6L
  83. #define FIBB_PURE    5L
  84.  
  85. #define FIBF_HIDDEN    (1L << FIBB_HIDDEN)
  86. #define FIBF_SCRIPT    (1L << FIBB_SCRIPT)
  87. #define FIBF_PURE    (1L << FIBB_PURE)
  88. #endif
  89.  
  90. #define MAXARGS        50
  91. #define NULL_PRIM    (struct primary *) NULL
  92. #define EQ(x,y)        (strcmp(x, y) == 0)
  93. #define PROTECTION    (FIBF_READ | FIBF_WRITE | FIBF_EXECUTE | FIBF_DELETE)
  94. #define STATUS        (FIBF_HIDDEN | FIBF_SCRIPT | FIBF_PURE | FIBF_ARCHIVE | PROTECTION)
  95.  
  96. /* boolean expression node structure */
  97.  
  98. struct node {
  99.     unsigned long        type;
  100.     struct node    *first;
  101.     struct node    *second;
  102. };
  103.  
  104. /* Node types - must be different from primary node types (below) */
  105.  
  106. #define OR    0x000000ff
  107. #define AND    0x0000ff00
  108. #define NOT    0x00ff0000
  109.  
  110. /* structure to hold interpreted primary information */
  111.  
  112. struct primary {
  113.     unsigned long        type;
  114.     unsigned long        size;
  115.     char                *data[MAXARGS];
  116. };
  117.  
  118. /* start of compiled expression tree */
  119.  
  120. struct node *node_head;
  121.  
  122. /* Primary types */
  123.  
  124. #define PRINT    0x00000001
  125. #define NAME    0x00000002
  126. #define SIZE    0x00000004
  127. #define TYPE    0x00000008
  128. #define EXEC    0x00000010
  129. #define NEWER    0x00000020
  130. #define MTIME    0x00000040
  131. #define PERM    0x00000080
  132. #define PROT    0x00000100
  133. #define PRIMS    0x0000ffff
  134.  
  135. /* type qualifiers */
  136.  
  137. #define DIRECT    0x00010000        /* directory for -type */
  138. #define PLAIN    0x00020000        /* plain file for -type */
  139. #define PROMPT    0x00040000        /* prompt for EXEC */
  140. #define LT        0x00080000        /* greater than */
  141. #define GT        0x00100000        /* less than */
  142. #define CHAR    0x00200000        /* use characters in -size check */
  143. #define QUALS    0xffff0000
  144.  
  145. int breakflag = FALSE;
  146.  
  147. char *path = NULL;                /* memory to hold full path name */
  148. int p_alloc = 500;
  149.  
  150. struct DateStamp date;
  151.  
  152. /* manx releases the memory allocated by calloc when you call exit() */
  153.  
  154. extern char        *calloc();
  155. extern char        *malloc();
  156.  
  157. main(argc, argv)
  158. int argc;
  159. char *argv[];
  160. {
  161.     register struct FileLock *start;
  162.     register i;
  163.     extern struct node *compile();
  164.  
  165.     DateStamp(&date);
  166.  
  167.     /* must be at least three arguments */
  168.  
  169.     if (argc < 3) {
  170.         fprintf(stderr, "Usage: find <path-list> <expression>\n");
  171.         exit(1);
  172.     }
  173.  
  174.     /* find the start of the boolean expression */
  175.  
  176.     for (i = 1 ; argv[i][0] != '-' && argv[i][0] != '!' && argv[i][0] != '(' ; i++);
  177.     if (i == 1) {
  178.         /* no path name list */
  179.         fprintf(stderr, "Usage: find <path-list> <expression>\n");
  180.         exit(1);
  181.     }
  182.  
  183.     /* compile the boolean expression */
  184.  
  185.     if (node_head = compile(argc - i, &argv[i])) {
  186.  
  187.         /* search each path-name specified */
  188.  
  189.         for (i = 1 ; argv[i][0] != '-' && argv[i][0] != '!' && argv[i][0] != '(' ; ++i) {
  190.             start = Lock(argv[i], ACCESS_READ);
  191.             if (start == NULL) {
  192.                 fprintf(stderr, "can't access '%s'\n", argv[i]);
  193.                 continue;
  194.             }
  195.  
  196.             search(start, argv[i]);
  197.             UnLock(start);
  198.  
  199.             if (path) {
  200.                 free(path);
  201.                 path = (char *) NULL;
  202.                 p_alloc = 500;
  203.             }
  204.         }
  205.     }
  206.  
  207.     exit(0);
  208. }
  209.  
  210. /* search the given directory and for each file
  211.  * execute the boolean expression.
  212.  */
  213.  
  214. search(lock, name)
  215. register struct FileLock *lock;
  216. register char *name;
  217. {
  218.     register struct FileInfoBlock *fib;
  219.     register struct FileLock *nlock;
  220.     char *prev = NULL, *file;
  221.     int ret;
  222.  
  223.     fib = (struct FileInfoBlock *) AllocMem((long) sizeof(struct FileInfoBlock), MEMF_CLEAR);
  224.     if (fib == NULL) {
  225.         fprintf(stderr, "can't allocate file info block\n");
  226.         return(0);
  227.     }
  228.  
  229.     /* save current position in full path name */
  230.  
  231.     if (path)
  232.         prev = path + strlen(path);
  233.  
  234.     /* examine initial path name */
  235.  
  236.     if (Examine(lock, fib)) {
  237.  
  238.         /* execute the expression on the inital path */
  239.  
  240.         execute(node_head, fib, name);
  241.  
  242.         if (name)
  243.             ret = add_pname(name);
  244.         else
  245.             ret = add_pname(fib->fib_FileName);
  246.  
  247.         if (ret == 0) {
  248.             fprintf(stderr, "out of memory\n");
  249.             FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  250.             return(0);
  251.         }
  252.  
  253.         if (fib->fib_DirEntryType <= 0) {
  254.  
  255.             /* if initial path name is not a directory then we just return */
  256.  
  257.             if (prev)
  258.                 *prev = '\0';
  259.             FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  260.             return(0);
  261.         }
  262.  
  263.         /* examine directory contents */
  264.  
  265.         while(ExNext(lock, fib)) {
  266.             if (breakflag) break;
  267.  
  268.             /* recurse if we have found a directory */
  269.  
  270.             if (fib->fib_DirEntryType > 0) {
  271.                 file = malloc(strlen(path) + strlen(fib->fib_FileName) + 1);
  272.                 if (file == NULL) {
  273.                     fprintf(stderr, "out of memory\n");
  274.                     breakflag = TRUE;
  275.                     break;
  276.                 }
  277.                 strcpy(file, path);
  278.                 strcat(file, fib->fib_FileName);
  279.                 nlock = Lock(file, ACCESS_READ);
  280.                 if (nlock == NULL)
  281.                     fprintf(stderr, "locking error - %s\n", file);
  282.                 else {
  283.                     search(nlock, NULL);
  284.                     UnLock(nlock);
  285.                 }
  286.                 free(file);
  287.             }
  288.             else
  289.                 execute(node_head, fib, NULL);
  290.  
  291.             if (SetSignal(0L, 0L) & SIGBREAKF_CTRL_C) {
  292.                 breakflag = TRUE;
  293.                 break;
  294.             }
  295.         }
  296.     }
  297.  
  298.     if (prev)
  299.         *prev = '\0';
  300.     FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  301. }
  302.  
  303. add_pname(name)
  304. register char *name;
  305. {
  306.     register char *tmp;
  307.     register char c;
  308.  
  309.     if (path == NULL) {
  310.         path = calloc(1, p_alloc);
  311.         if (path == NULL)
  312.             return(0);
  313.     }
  314.  
  315.     while (strlen(name) + strlen(path) + 1 > p_alloc) {
  316.         p_alloc *= 2;
  317.         tmp = calloc(1, p_alloc);
  318.         if (tmp == NULL)
  319.             return(0);
  320.  
  321.         strcpy(tmp, path);
  322.         free(path);
  323.         path = tmp;
  324.     }
  325.  
  326.     if (strlen(path) && (c = path[strlen(path) - 1]) != ':' && c != '/')
  327.         strcat(path, "/");
  328.  
  329.     strcat(path, name);
  330.     if (strlen(path) && (c = path[strlen(path) - 1]) != ':' && c != '/')
  331.         strcat(path, "/");
  332.  
  333.     return(1);
  334. }
  335.  
  336. /* execute the boolean expression on the given file */
  337.  
  338. execute(cnode, fib, name)
  339. register struct node *cnode;
  340. register struct FileInfoBlock *fib;
  341. char *name;
  342. {
  343.     register struct primary *prim;
  344.     register long checksize;
  345.     register j;
  346.     register struct DateStamp *ds;
  347.     char *file, ok[10];
  348.     char *av[MAXARGS + 1];
  349.  
  350.     /* check node type */
  351.  
  352.     if (cnode->type == AND)
  353.         if  (execute(cnode->first, fib, name))
  354.             return(execute(cnode->second, fib, name));
  355.         else
  356.             return(0);
  357.  
  358.     else if (cnode->type == OR)
  359.         if  (execute(cnode->first, fib, name))
  360.             return(1);
  361.         else
  362.             return(execute(cnode->second, fib, name));
  363.  
  364.     else if (cnode->type == NOT)
  365.         return(!execute(cnode->first, fib, name));
  366.  
  367.     else {
  368.  
  369.         /* we have an actual primary */
  370.  
  371.         if (name == NULL)
  372.             name = fib->fib_FileName;
  373.  
  374.         prim = (struct primary *) cnode;
  375.         switch (prim->type & PRIMS) {
  376.  
  377.         case PRINT:
  378.  
  379.             if (*path)
  380.                 printf("%s%s\n", path, name);
  381.             else
  382.                 printf("%s\n", name);
  383.             return(1);
  384.  
  385.         case NAME:
  386.  
  387.             if (compare_ok(prim->data[0], name))
  388.                 return(1);
  389.             else
  390.                 return(0);
  391.  
  392.         case SIZE:
  393.  
  394.             if (prim->type & CHAR)
  395.                 checksize = fib->fib_Size;
  396.             else
  397.                 checksize = fib->fib_NumBlocks;
  398.  
  399.             if (((prim->type & GT) && (checksize > prim->size) ) ||
  400.                 ((prim->type & LT) && (checksize < prim->size) ) ||
  401.                 ((prim->type & (GT | LT)) == 0 && (checksize == prim->size)))
  402.                 return(1);
  403.             else
  404.                 return(0);
  405.  
  406.         case TYPE:
  407.  
  408.             switch (prim->type & QUALS | (fib->fib_DirEntryType > 0)) {
  409.  
  410.             case DIRECT:
  411.             case (PLAIN | 1):
  412.                 return(0);
  413.  
  414.             default:
  415.                 return(1);
  416.             }
  417.  
  418.         case EXEC:
  419.  
  420.             for (j = 0 ; prim->data[j] ; j++)
  421.                 if (EQ("{}", prim->data[j])) {
  422.                     file = malloc(strlen(path) + strlen(name) + 1);
  423.                     if (file == NULL) {
  424.                         fprintf(stderr, "out of memory\n");
  425.                         return(0);
  426.                     }
  427.                     strcpy(file, path);
  428.                     strcat(file, name);
  429.                     av[j] = file;
  430.                 }
  431.                 else
  432.                     av[j] = prim->data[j];
  433.             av[j] = NULL;
  434.  
  435.             if (!(prim->type & PROMPT) || (pr_cmd(av) && gets(ok) &&
  436.                  ((ok[0] == 'y') || (ok[0] == 'Y')))) {
  437.                 if (fexecv(av[0], av) == -1)
  438.                     return(0);
  439.                 else if (wait())
  440.                     return(0);
  441.                 else
  442.                     return(1);
  443.             }
  444.  
  445.             return(0);
  446.  
  447.         case NEWER:
  448.  
  449.             ds = (struct DateStamp *) prim->data[0];
  450.             if (fib->fib_Date.ds_Days > ds->ds_Days)
  451.                 return(1);
  452.             else if (fib->fib_Date.ds_Days == ds->ds_Days &&
  453.                      fib->fib_Date.ds_Minute > ds->ds_Minute)
  454.                 return(1);
  455.             else if (fib->fib_Date.ds_Days == ds->ds_Days &&
  456.                      fib->fib_Date.ds_Minute == ds->ds_Minute &&
  457.                      fib->fib_Date.ds_Tick > ds->ds_Tick)
  458.                 return(1);
  459.             else
  460.                 return(0);
  461.  
  462.         case MTIME:
  463.  
  464.             checksize = date.ds_Days - fib->fib_Date.ds_Days;
  465.  
  466.             if (((prim->type & GT) && (checksize > prim->size) ) ||
  467.                 ((prim->type & LT) && (checksize < prim->size) ) ||
  468.                 ((prim->type & (GT | LT)) == 0 && (checksize == prim->size)))
  469.                 return(1);
  470.             else
  471.                 return(0);
  472.  
  473.         case PERM:
  474.  
  475.             if ((fib->fib_Protection & STATUS) == prim->size)
  476.                 return(1);
  477.             else
  478.                 return(0);
  479.  
  480.         case PROT:
  481.  
  482.             if ((fib->fib_Protection & prim->size) == prim->size)
  483.                 return(1);
  484.             else
  485.                 return(0);
  486.  
  487.         }
  488.         return(0);
  489.     }
  490. }
  491.  
  492. /* print the command to be executed on the screen */
  493.  
  494. pr_cmd(av)
  495. char *av[];
  496. {
  497.     register j;
  498.  
  499.     printf("< ");
  500.     for (j = 0 ; av[j] ; j++) printf("%s ", av[j]);
  501.     printf("> ? ");
  502.     return(1);
  503. }
  504.  
  505. /* compile the boolean expression: returns a pointer to the start
  506.  * of the compiled expression tree, or NULL if a failure occurs.
  507.  */
  508.  
  509. struct node *
  510. compile(argc, argv)
  511. int argc;
  512. char *argv[];
  513. {
  514.     register i, j, scan;
  515.     register struct primary *prim;
  516.     register struct node *node_head = (struct node *) NULL, *tmp_node;
  517.  
  518.     for(i = 0 ; i < argc ; i++) {
  519.  
  520.         prim = (struct primary *) calloc(1, sizeof(struct primary));
  521.         if (prim == NULL_PRIM) {
  522.             fprintf(stderr, "out memory in primary interpretation\n");
  523.             exit(5);
  524.         }
  525.  
  526.  
  527.         if (EQ("-o", argv[i])) {
  528.             free(prim);
  529.  
  530.             /* -o cannot be the first argument */
  531.  
  532.             if (node_head == NULL_PRIM) {
  533.                 fprintf(stderr, "misplaced 'or' operator ... ignored\n");
  534.                 continue;
  535.             }
  536.  
  537.             else {
  538.  
  539.                 /* create OR node */
  540.  
  541.                 tmp_node = (struct node *) calloc(1, sizeof(struct node));
  542.                 if (tmp_node == NULL) {
  543.                     fprintf(stderr, "out of memory in expression compilation");
  544.                     exit(5);
  545.                 }
  546.                 tmp_node->type = OR;
  547.                 tmp_node->first = node_head;
  548.  
  549.                 /* compile rest of expression and attach it to OR node */
  550.  
  551.                 if ((tmp_node->second = compile(argc - i - 1, argv + i + 1)) == NULL) {
  552.                     free(tmp_node);
  553.                     return(node_head);
  554.                 }
  555.                 else
  556.                     return(tmp_node);
  557.             }
  558.         }
  559.  
  560.         else if (EQ("(", argv[i])) {
  561.             free(prim);
  562.  
  563.             /* scan to matching brackets */
  564.  
  565.             for (j = 0, scan = 0 ; ++i < argc && (!EQ(")", argv[i]) || scan != 0) ; j++) {
  566.                 if (EQ("(", argv[i])) scan++;
  567.                 if (EQ(")", argv[i])) scan--;
  568.             }
  569.  
  570.             if (i >= argc) {
  571.                 fprintf(stderr, "unmatched bracket\n");
  572.                 exit(5);
  573.             }
  574.  
  575.             if (j == 0) {
  576.                 fprintf(stderr, "empty brackets ... ignored\n");
  577.                 continue;
  578.             }
  579.  
  580.             /* compile what is in the brackets */
  581.  
  582.             if ((prim = (struct primary *) compile(j, argv + i - j)) == NULL)
  583.                 continue;
  584.         }
  585.  
  586.         else if (EQ("!", argv[i])) {
  587.             if (++i >= argc) {
  588.                 fprintf(stderr, "trailing '!' ignored\n");
  589.                 continue;
  590.             }
  591.             if (EQ("-o", argv[i])) {
  592.                 fprintf(stderr, "illegal 'or' operator placement\n");
  593.                 exit(5);
  594.             }
  595.  
  596.             tmp_node = (struct node *) calloc(1, sizeof(struct node));
  597.             if (tmp_node == NULL) {
  598.                 fprintf(stderr, "out of memory in expression compilation\n");
  599.                 exit(5);
  600.             }
  601.             tmp_node->type = NOT;
  602.  
  603.             if (EQ("(", argv[i])) {
  604.  
  605.                 /* scan to matching bracket */
  606.  
  607.                 for (j = 0, scan = 0 ; ++i < argc && (!EQ(")", argv[i]) || scan != 0) ; j++) {
  608.                     if (EQ("(", argv[i])) scan++;
  609.                     if (EQ(")", argv[i])) scan--;
  610.                 }
  611.  
  612.                 if (i >= argc) {
  613.                     fprintf(stderr, "unmatched bracket\n");
  614.                     exit(5);
  615.                 }
  616.  
  617.                 if (j == 0) {
  618.                     fprintf(stderr, "empty brackets ... ignored\n");
  619.                     free(tmp_node);
  620.                     continue;
  621.                 }
  622.  
  623.                 /* compile what is in the brackets */
  624.  
  625.                 if ((tmp_node->first = compile(j, argv + i - j)) == NULL)
  626.                     continue;
  627.             }
  628.             else {
  629.                 tmp_node->first = (struct node *) prim;
  630.                 i += interpret(prim, argc - i, argv + i);
  631.             }
  632.             prim = (struct primary *) tmp_node;
  633.         }
  634.  
  635.         else
  636.             i += interpret(prim, argc - i, argv + i);
  637.  
  638.         /* attach interpreted primary to expression tree */
  639.  
  640.         if (node_head == NULL)
  641.             node_head = (struct node *) prim;
  642.         else {
  643.             tmp_node = (struct node *) calloc(1, sizeof(struct node));
  644.             if (tmp_node == NULL) {
  645.                 fprintf(stderr, "out of memory in expression compilation\n");
  646.                 exit(5);
  647.             }
  648.             tmp_node->type   = AND;
  649.             tmp_node->first  = node_head;
  650.             tmp_node->second = (struct node *) prim;
  651.             node_head        = tmp_node;
  652.         }
  653.     }
  654.  
  655.     return(node_head);
  656. }
  657.  
  658. /* interpret a primary */
  659.  
  660. interpret(prim, argc, argv)
  661. struct primary *prim;
  662. char *argv[];
  663. {
  664.     register i, j;
  665.     register struct FileLock *lock;
  666.     register struct FileInfoBlock *fib;
  667.     register struct DateStamp *ds;
  668.     char *numstr;
  669.     extern unsigned long atol();
  670.  
  671.     for (i = 0 ; i < argc ; i++) {
  672.  
  673.         if (EQ("-print", argv[i]))
  674.             prim->type = PRINT;
  675.  
  676.         else if (EQ("-name", argv[i])) {
  677.             prim->type = NAME;
  678.             prim->data[0] = argv[++i];
  679.         }
  680.  
  681.         else if (EQ("-size", argv[i])) {
  682.             prim->type = SIZE;
  683.  
  684.             /* get required size */
  685.  
  686.             numstr = argv[++i];
  687.  
  688.             if (*numstr == '+') {
  689.                 prim->type |= GT;
  690.                 numstr++;
  691.             }
  692.  
  693.             else if (*numstr == '-') {
  694.                 prim->type |= LT;
  695.                 numstr++;
  696.             }
  697.  
  698.             if (numstr[strlen(numstr) - 1] == 'c') {
  699.                 prim->type |= CHAR;
  700.                 numstr[strlen(numstr) - 1] = '\0';
  701.             }
  702.  
  703.             prim->size = atol(numstr);
  704.         }
  705.  
  706.         else if (EQ("-type", argv[i])) {
  707.             prim->type = TYPE;
  708.             if (EQ(argv[++i], "d"))
  709.                 prim->type |= DIRECT;
  710.             else if (EQ(argv[i], "f"))
  711.                 prim->type |= PLAIN;
  712.             else {
  713.                 fprintf(stderr, "illegal file type specified\n");
  714.                 exit(5);
  715.             }
  716.         }
  717.  
  718.         else if (EQ("-exec", argv[i])) {
  719.             prim->type = EXEC;
  720.  
  721.             /* scan to ending ';', saving pointers to arguments */
  722.  
  723.             for (j=0 ; (j<MAXARGS) && (++i < argc) && !EQ(";",argv[i]) ; j++)
  724.                 prim->data[j] = argv[i];
  725.  
  726.             if (i >= argc) {
  727.                 fprintf(stderr, "no ending ';' on command\n");
  728.                 exit(5);
  729.             }
  730.  
  731.             else if (j >= MAXARGS) {
  732.                 fprintf(stderr, "command too long\n");
  733.                 exit(5);
  734.             }
  735.  
  736.             else
  737.                 argv[j] = NULL;
  738.         }
  739.  
  740.         else if (EQ("-ok", argv[i])) {
  741.             prim->type = EXEC | PROMPT;
  742.  
  743.             /* scan to ending ';', saving pointers to arguments */
  744.  
  745.             for (j=0 ; (j<MAXARGS) && (++i < argc) && !EQ(";",argv[i]) ; j++)
  746.                 prim->data[j] = argv[i];
  747.  
  748.             if (i >= argc) {
  749.                 fprintf(stderr, "no ending ';' on command\n");
  750.                 exit(5);
  751.             }
  752.  
  753.             else if (j >= MAXARGS) {
  754.                 fprintf(stderr, "command too long\n");
  755.                 exit(5);
  756.             }
  757.  
  758.             else
  759.                 argv[j] = NULL;
  760.         }
  761.  
  762.         else if (EQ("-newer", argv[i])) {
  763.             prim->type = NEWER;
  764.  
  765.             if (lock = Lock(argv[++i])) {
  766.                 fib = (struct FileInfoBlock *) AllocMem((long) sizeof(struct FileInfoBlock), MEMF_CLEAR);
  767.                 if (fib == NULL) {
  768.                     fprintf(stderr, "no mem for -newer test\n");
  769.                     UnLock(lock);
  770.                     exit(5);
  771.                 }
  772.  
  773.                 if (Examine(lock, fib) == 0) {
  774.                     fprintf(stderr, "could not examine %s\n", argv[i]);
  775.                     FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  776.                     UnLock(lock);
  777.                     exit(5);
  778.                 }
  779.  
  780.                 /* save date stamp of given file */
  781.  
  782.                 ds = (struct DateStamp *) calloc(1, sizeof(struct DateStamp));
  783.                 if (ds == NULL) {
  784.                     fprintf(stderr, "no mem for DateStamp on %s\n", argv[i]);
  785.                     FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  786.                     UnLock(lock);
  787.                     exit(5);
  788.                 }
  789.  
  790.                 prim->data[0] = (char *) ds;
  791.                 *ds = fib->fib_Date;
  792.  
  793.                 FreeMem(fib, (long) sizeof(struct FileInfoBlock));
  794.                 UnLock(lock);
  795.             }
  796.  
  797.             else {
  798.                 fprintf(stderr, "unable to access %s\n", argv[i]);
  799.                 exit(5);
  800.             }
  801.         }
  802.  
  803.         else if (EQ("-mtime", argv[i])) {
  804.             prim->type = MTIME;
  805.  
  806.             /* get required number of days */
  807.  
  808.             numstr = argv[++i];
  809.  
  810.             if (*numstr == '+') {
  811.                 prim->type |= GT;
  812.                 numstr++;
  813.             }
  814.             else if (*numstr == '-') {
  815.                 prim->type |= LT;
  816.                 numstr++;
  817.             }
  818.  
  819.             prim->size = atol(numstr);
  820.         }
  821.  
  822.         else if (EQ("-perm", argv[i])) {
  823.             prim->type = PERM;
  824.             prim->size = PROTECTION;
  825.  
  826.             /* assemble desired protection bits */
  827.  
  828.             for(i++, j = 0 ; argv[i][j] ; j++) {
  829.                 switch(argv[i][j]) {
  830.  
  831.                 case 'n':
  832.                     if (prim->size != PROTECTION)
  833.                         fprintf(stderr, "'n' permission code overriding other given codes \n");
  834.  
  835.                     prim->size = PROTECTION;
  836.                     return(i);
  837.  
  838.                 case 'h':
  839.                     prim->size |= FIBF_HIDDEN;
  840.                     break;
  841.  
  842.                 case 's':
  843.                     prim->size |= FIBF_SCRIPT;
  844.                     break;
  845.  
  846.                 case 'p':
  847.                     prim->size |= FIBF_PURE;
  848.                     break;
  849.  
  850.                 case 'a':
  851.                     prim->size |= FIBF_ARCHIVE;
  852.                     break;
  853.  
  854.                 case 'r':
  855.                     prim->size &= ~FIBF_READ;
  856.                     break;
  857.  
  858.                 case 'w':
  859.                     prim->size &= ~FIBF_WRITE;
  860.                     break;
  861.  
  862.                 case 'e':
  863.                     prim->size &= ~FIBF_EXECUTE;
  864.                     break;
  865.  
  866.                 case 'd':
  867.                     prim->size &= ~FIBF_DELETE;
  868.                     break;
  869.  
  870.                 default:
  871.                     fprintf(stderr, "unknown permission code '%c' ... ignored\n", argv[i][j]);
  872.                     break;
  873.                 }
  874.             }
  875.         }
  876.  
  877.         else if (EQ("-prot", argv[i])) {
  878.             prim->type = PROT;
  879.             prim->size = 0;
  880.  
  881.             /* assemble desired protection bits */
  882.  
  883.             for(i++, j = 0 ; argv[i][j] ; j++) {
  884.                 switch(argv[i][j]) {
  885.  
  886.                 case 'h':
  887.                     prim->size |= FIBF_HIDDEN;
  888.                     break;
  889.  
  890.                 case 's':
  891.                     prim->size |= FIBF_SCRIPT;
  892.                     break;
  893.  
  894.                 case 'p':
  895.                     prim->size |= FIBF_PURE;
  896.                     break;
  897.  
  898.                 case 'a':
  899.                     prim->size |= FIBF_ARCHIVE;
  900.                     break;
  901.  
  902.                 case 'r':
  903.                     prim->size |= FIBF_READ;
  904.                     break;
  905.  
  906.                 case 'w':
  907.                     prim->size |= FIBF_WRITE;
  908.                     break;
  909.  
  910.                 case 'e':
  911.                     prim->size |= FIBF_EXECUTE;
  912.                     break;
  913.  
  914.                 case 'd':
  915.                     prim->size |= FIBF_DELETE;
  916.                     break;
  917.  
  918.                 default:
  919.                     fprintf(stderr, "unknown protection code '%c' ... ignored\n", argv[i][j]);
  920.                     break;
  921.                 }
  922.             }
  923.         }
  924.  
  925.         else {
  926.             fprintf(stderr, "unknown primary: %s\n", argv[i]);
  927.             exit(5);
  928.         }
  929.  
  930.         return(i);
  931.     }
  932. }
  933.  
  934. /*
  935.  * Compare a wild card name with a normal name.
  936.  * Taken from Matt Dillon's csh program.
  937.  */
  938.  
  939. #define MAXB   8
  940.  
  941. compare_ok(wild, name)
  942. char *wild, *name;
  943. {
  944.    register char *w = wild;
  945.    register char *n = name;
  946.    char *back[MAXB][2];
  947.    register char s1, s2;
  948.    int    bi = 0;
  949.  
  950.    while (*n || *w) {
  951.       switch (*w) {
  952.       case '*':
  953.      if (bi == MAXB) {
  954.         fprintf(stderr,"Too many levels of '*'\n");
  955.         return (0);
  956.      }
  957.      back[bi][0] = w;
  958.      back[bi][1] = n;
  959.      ++bi;
  960.      ++w;
  961.      continue;
  962. goback:
  963.      --bi;
  964.      while (bi >= 0 && *back[bi][1] == '\0')
  965.         --bi;
  966.      if (bi < 0)
  967.         return (0);
  968.      w = back[bi][0] + 1;
  969.      n = ++back[bi][1];
  970.      ++bi;
  971.      continue;
  972.       case '?':
  973.      if (!*n) {
  974.         if (bi)
  975.            goto goback;
  976.         return (0);
  977.      }
  978.      break;
  979.       default:
  980.      s1 = (*n >= 'A' && *n <= 'Z') ? *n - 'A' + 'a' : *n;
  981.      s2 = (*w >= 'A' && *w <= 'Z') ? *w - 'A' + 'a' : *w;
  982.      if (s1 != s2) {
  983.         if (bi)
  984.            goto goback;
  985.         return (0);
  986.      }
  987.      break;
  988.       }
  989.       if (*n)  ++n;
  990.       if (*w)  ++w;
  991.    }
  992.    return (1);
  993. }
  994. SHAR_EOF
  995. cat << \SHAR_EOF > makefile
  996. OBJ = find.o
  997.  
  998. .c.o:
  999.     cc -E200 $*.c
  1000.  
  1001. find:        Makefile $(OBJ)
  1002.     ln -o find $(OBJ) -lc
  1003.  
  1004. find.o:        find.c
  1005.  
  1006. find.uue:    find
  1007.     uuencode >find.uue find find
  1008.  
  1009. shar:        shar1 shar2 shar3
  1010.  
  1011. shar1:
  1012.     shar -a find.c makefile > find.shar1
  1013.  
  1014. shar2:
  1015.     shar -a find.doc README > find.shar2
  1016.  
  1017. shar3:        find.uue
  1018.     shar -a find.uue > find.shar3
  1019. SHAR_EOF
  1020. #    End of shell archive
  1021. exit 0
  1022. -- 
  1023. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  1024. Have five nice days.
  1025.